package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.user.client.UserListenProcessFeignClient;
import com.atguigu.tingshu.vo.base.user.UserInfo;
import com.atguigu.tingshu.vo.base.user.UserPaidTrack;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.order.TrackOrderVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {
    @Resource
    private TrackInfoMapper trackInfoMapper;
    @Resource
    private AlbumInfoService albumInfoService;
    @Resource
    private VodService vodService;
    @Resource
    private TrackStatMapper trackStatMapper;
    @Resource
    private UserInfoFeignClient userInfoFeignClient;
    @Resource
    private UserListenProcessFeignClient userListenProcessFeignClient;
    @Resource
    private VodConstantProperties vodConstantProperties;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        Long userId = AuthContextHolder.getUserId();
        //设置用户id
        trackInfo.setUserId(userId == null ? 1 : userId);
        //查询当前专辑的信息
        AlbumInfo albumInfo = albumInfoService.getById(trackInfoVo.getAlbumId());
        //设置新增音频的排列序号
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() == 0 ? 1 : albumInfo.getIncludeTrackCount() + 1);
        //获取上传vod音频 的详情
        TrackMediaInfoVo mediaDetail = vodService.getMediaDetail(trackInfoVo.getMediaFileId());
        trackInfo.setMediaDuration(BigDecimal.valueOf(mediaDetail.getDuration()));
        trackInfo.setMediaUrl(mediaDetail.getMediakUrl());
        trackInfo.setMediaSize(mediaDetail.getSize());
        trackInfo.setMediaType(mediaDetail.getType());
        //设置音频来源
        trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
        //设置审核状态
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        //保存音频基本信息
        save(trackInfo);
        Long trackInfoId = trackInfo.getId();

        //初始化音频统计信息
        initTrackStat(trackInfoId, SystemConstant.TRACK_STAT_PLAY);
        initTrackStat(trackInfoId, SystemConstant.TRACK_STAT_COLLECT);
        initTrackStat(trackInfoId, SystemConstant.TRACK_STAT_PRAISE);
        initTrackStat(trackInfoId, SystemConstant.TRACK_STAT_COMMENT);

        //更新专辑表的音频总数量
        albumInfo.setIncludeTrackCount(trackInfo.getOrderNum());
        albumInfoService.updateById(albumInfo);
    }

    @Override
    public Page<TrackListVo> findUserTrackPage(Page<TrackListVo> iPage, TrackInfoQuery query) {
        query.setUserId(AuthContextHolder.getUserId() == null ? 1 : AuthContextHolder.getUserId());
        return trackInfoMapper.findUserTrackPage(iPage, query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        TrackInfo trackInfo = getById(id);
        //删除音频信息
        removeById(id);
        //删除统计信息
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, id));
        //更新专辑表的音频总数量
        AlbumInfo albumInfo = albumInfoService.getById(trackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoService.updateById(albumInfo);
        //删除vod云点播上的音频
        vodService.delMediaDetail(trackInfo.getMediaFileId());
    }

    @Override
    public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
        TrackInfo trackInfo = getById(id);
        String mediaFileIdOld = trackInfo.getMediaFileId();  //获取旧的音频文件id
        String mediaFileIdNew = trackInfoVo.getMediaFileId();//获取新的音频文件id

        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setId(id);

        //判断音频文件是否被更改
        if (!mediaFileIdOld.equals(mediaFileIdNew)) {
            //删除vod上的音频文件
            vodService.delMediaDetail(mediaFileIdOld);
            //获取上传vod音频 的详情
            TrackMediaInfoVo mediaDetail = vodService.getMediaDetail(mediaFileIdNew);
            trackInfo.setMediaDuration(BigDecimal.valueOf(mediaDetail.getDuration()));
            trackInfo.setMediaUrl(mediaDetail.getMediakUrl());
            trackInfo.setMediaSize(mediaDetail.getSize());
            trackInfo.setMediaType(mediaDetail.getType());
        }
        trackInfoMapper.updateById(trackInfo);
    }

    @Override
    public Page<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> iPage, Long albumId) {
        //根据专辑id获取专辑信息
        AlbumInfo albumInfo = albumInfoService.getById(albumId);
        if (albumInfo == null) return null;
        //分页查询声音列表
        Page<AlbumTrackListVo> trackListVoPage = trackInfoMapper.findAlbumTrackPage(iPage, albumId);
        //获取当前页的声音列表集合
        List<AlbumTrackListVo> trackList = trackListVoPage.getRecords();
        if (CollectionUtils.isEmpty(trackList)) return trackListVoPage;
        //判断专辑为免费专辑，则直接返回
        if (albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) return trackListVoPage;
        //获取需要付费的声音列表
        List<AlbumTrackListVo> trackListVos = trackList.stream().filter(track -> track.getOrderNum() > albumInfo.getTracksForFree()).toList();
        if (CollectionUtils.isEmpty(trackListVos)) return trackListVoPage;
        //若不为免费专辑则查询登录状态
        Long userId = AuthContextHolder.getUserId();
        if (userId == null) {
            trackListVos.forEach(track -> track.setIsShowPaidMark(true));
        }
        //查询用户信息
        Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfo(userId);
        Assert.notNull(userInfoResult, "声音分页查询时,获取登录用户信息失败！");
        UserInfo userInfo = userInfoResult.getData();
        //判断当前用户是否是未过期的VIP用户并且专辑是VIP免费
        if (userInfo.getIsVip() == 1 && userInfo.getVipExpireTime()
                .after(new Date()) && albumInfo.getPayType()
                .equals(SystemConstant.ALBUM_PAY_TYPE_VIP_FREE)) return trackListVoPage;
        //查询用户是否购买过该专辑
        Result<Boolean> booleanResult = userInfoFeignClient.isPayAlbum(albumId);
        Assert.notNull(booleanResult, "声音分页查询时,查询用户是否购买过该专辑接口调用失败！");
        Boolean flag = booleanResult.getData();
        if (flag) return trackListVoPage;
        //查询当前用户是否购买当前专辑下的声音
        Result<List<UserPaidTrack>> payTrackResult = userInfoFeignClient.isPayTrack(albumId);
        Assert.notNull(payTrackResult, "声音分页查询时,查询用户是否购买过该专辑下的声音接口调用失败！");
        List<UserPaidTrack> paidTracks = payTrackResult.getData();
        if (CollectionUtils.isEmpty(paidTracks)) {
            trackListVos.forEach(track -> track.setIsShowPaidMark(true));
        }
        List<Long> trackIds = paidTracks.stream().map(UserPaidTrack::getTrackId).toList();
        trackListVos.forEach(track -> {
            if (!trackIds.contains(track.getTrackId())) {
                track.setIsShowPaidMark(true);
            }
        });
        return trackListVoPage;
    }

    @Override
    public TrackStatVo getTrackStatVo(Long id) {
        return trackInfoMapper.getTrackStatVo(id);
    }

    @Override
    public Map<String, Object> getPlayToken(Long trackId) {
        Long userId = AuthContextHolder.getUserId();
        if (userId == null) throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        TrackInfo trackInfo = this.getById(trackId);
        Assert.notNull(trackInfo, "声音信息不能为空！");
        AlbumInfo albumInfo = this.albumInfoService.getById(trackInfo.getAlbumId());
        Assert.notNull(albumInfo, "专辑信息不能为空！");

        if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())
                && trackInfo.getOrderNum() > albumInfo.getSecondsForFree()) {
            Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfo(userId);
            Assert.notNull(userInfoResult, "获取播放凭证时，获取用户信息失败");
            UserInfo userInfo = userInfoResult.getData();
            Assert.notNull(userInfo, "用户信息不能为空！");

            if (userInfo.getIsVip() == 0 || userInfo.getVipExpireTime().before(new Date()) || !SystemConstant.ALBUM_PAY_TYPE_VIP_FREE.equals(albumInfo.getPayType())) {
                Result<Boolean> booleanResult = userInfoFeignClient.isPayAlbum(trackInfo.getAlbumId());
                Assert.notNull(booleanResult, "获取播放凭证时,获取用户是否购买过当前专辑失败！");
                Boolean flag = booleanResult.getData();
                if (!flag) {
                    Result<List<UserPaidTrack>> listResult = userInfoFeignClient.isPayTrack(trackId);
                    Assert.notNull(listResult, "获取播放凭证时,获取用户是否购买过当前专辑下声音列表失败！");
                    List<UserPaidTrack> paidTracks = listResult.getData();
                    if (CollectionUtils.isEmpty(paidTracks)) throw new GuiguException(ResultCodeEnum.NO_BUY_NOT_SEE);
                }
            }
        }
        // 获取播放进度
        Result<BigDecimal> result = this.userListenProcessFeignClient.getTrackBreakSecond(trackId);
        Assert.notNull(result, "获取到跳出时间结果不能为空");
        BigDecimal breakSecond = result.getData();
        String playToken = this.vodService.getPlayToken(trackInfo.getMediaFileId());
        Map<String, Object> map = new HashMap<>();
        map.put("playToken", playToken);
        map.put("mediaFileId", trackInfo.getMediaFileId());
        map.put("breakSecond", breakSecond);
        map.put("appId", vodConstantProperties.getAppId());

        //获取下一个播放声音
        TrackInfo nextTrackInfo = this.getOne(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, trackInfo.getAlbumId())
                .gt(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .orderByAsc(TrackInfo::getOrderNum)
                .select(TrackInfo::getId).last("limit 1"));
        if (nextTrackInfo != null) map.put("nextTrackId", nextTrackInfo.getId());
        map.put("nextTrackId", 0L);
        return map;
    }

    @Override
    public List<TrackOrderVo> findUserTrackPaidList(Long trackId) {
        TrackInfo trackInfo = this.getById(trackId);
        if (trackInfo == null) return null;
        AlbumInfo albumInfo = this.albumInfoService.getById(trackInfo.getAlbumId());
        //获取当前声音及之后的所有付费声音
        List<Long> trackIds = this.trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, trackInfo.getAlbumId())
                .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .orderByAsc(TrackInfo::getOrderNum)).stream().map(TrackInfo::getId).toList();
        if (CollectionUtils.isEmpty(trackIds)) return null;
        //获取当前用户购买的此专辑下的声音列表
        Result<List<UserPaidTrack>> payTrackResult = this.userInfoFeignClient.isPayTrack(trackInfo.getAlbumId());
        Assert.notNull(payTrackResult, "获取声音购买方式时，获取当前用户购买该专辑下声音列表失败！");
        List<UserPaidTrack> paidTracks = payTrackResult.getData();

        List<TrackOrderVo> trackOrderVos = new ArrayList<>();
        //单集价格
        BigDecimal price = albumInfo.getPrice();

        List<Long> paidTrackIdList = new ArrayList<>();
        //判断是否购买
        if (CollectionUtils.isEmpty(paidTracks)) {//未购买
            paidTrackIdList = trackIds;
        } else {
            //购买过则获取该专辑已购买的声音的id
            List<Long> paidTrackIds = paidTracks.stream().map(UserPaidTrack::getTrackId).toList();
            //过滤出未购买的声音列表
            paidTrackIdList = trackIds.stream().filter(track -> !paidTrackIds.contains(track)).toList();
        }
        int count = paidTrackIdList.size();
        if (paidTrackIdList.contains(trackId))
            trackOrderVos.add(new TrackOrderVo().setName("本集").setPrice(price).setTrackCount(1));
        if (count >= 10)
            trackOrderVos.add(new TrackOrderVo().setName("后10集").setPrice(price.multiply(new BigDecimal(10))).setTrackCount(10));
        if (count >= 20)
            trackOrderVos.add(new TrackOrderVo().setName("后20集").setPrice(price.multiply(new BigDecimal(20))).setTrackCount(20));
        if (count >= 30)
            trackOrderVos.add(new TrackOrderVo().setName("后30集").setPrice(price.multiply(new BigDecimal(30))).setTrackCount(30));
        if (count >= 50)
            trackOrderVos.add(new TrackOrderVo().setName("后50集").setPrice(price.multiply(new BigDecimal(50))).setTrackCount(50));
        if (count > 1 && count % 10 != 0)
            trackOrderVos.add(new TrackOrderVo().setName("后" + count + "集").setPrice(price.multiply(new BigDecimal(count))).setTrackCount(count));
        return trackOrderVos;
    }

    @Override
    public List<TrackInfo> findPaidTrack(Long trackId, Integer trackCount) {
        if (trackCount <= 0) return null;
        TrackInfo trackInfo = this.getById(trackId);
        if (trackInfo == null) return null;
        Long albumId = trackInfo.getAlbumId();
        //封装查询条件
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .orderByAsc(TrackInfo::getOrderNum).select(TrackInfo::getId, TrackInfo::getAlbumId, TrackInfo::getTrackTitle, TrackInfo::getCoverUrl)
                .last("limit " + trackCount);
        //获取已经购买的当前专辑下的声音列表
        Result<List<UserPaidTrack>> listResult = userInfoFeignClient.isPayTrack(albumId);
        Assert.notNull(listResult, "购买声音时，获取用户购买声音列表失败！");
        List<UserPaidTrack> paidTrackList = listResult.getData();
        if (!CollectionUtils.isEmpty(paidTrackList)) {
            List<Long> trackIds = paidTrackList.stream().map(UserPaidTrack::getTrackId).toList();
            queryWrapper.notIn(TrackInfo::getId, trackIds);
        }
        return this.baseMapper.selectList(queryWrapper);
    }

    //初始化音频统计信息的方法
    private void initTrackStat(Long trackInfoId, String statType) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackInfoId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(0);
        trackStatMapper.insert(trackStat);
    }
}
